package asteroids.entity.equipment;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;

import org.apache.log4j.Logger;

import asteroids.engine.GameState;
import asteroids.engine.Utils;
import asteroids.entity.GameObject;
import asteroids.entity.Icing;
import asteroids.entity.Ship;
import asteroids.entity.weapon.Bullet;
import asteroids.factory.ShapeLib;

public class MADDevice extends Equipment
{
    Logger logger = Logger.getLogger(MADDevice.class);

    private double explosion_radius;
    private double max_explosion_radius;
    /*
     * keeps track of the explosion progress: 0 - not exploded yet 1 - warming
     * up 2 - BOOM 3 - cleanup?
     */
    private int phase;
    private long phaseStartTime; // when the current phase began
    private long currentTime; // how long we've been in the current phase
    private Icing placeholder;

    public MADDevice(Ship s, double boomSize)
    {
        super(s);

        updateAfterDeath = true;
        explosion_radius = 1;
        max_explosion_radius = boomSize;
        phase = 0;
        phaseStartTime = 0;
        currentTime = 0;

        objectShape = Utils.createPolarCircle(explosion_radius);

        // make sure the ship doesn't stop updating 'til we are done exploding.
        placeholder = new Icing(0, 0, true);
        ship.addIcing(placeholder);
    }

    public MADDevice(Ship s)
    {
        this(s, ShapeLib.shipLength * 5);
    }

    public void update(GameState state)
    {
        logger.trace("MADDevice.update()");
        if( !ship.isAlive() && ship.isActive() && phase == 0 )
        {
            // Start exploding!
            logger.trace("starting to asplode!");
            // drawMe = true; // enable drawing of this Equipment - only
            // necessary
            // for the circle

            // ensure we are at the ship's dying location
            x_position = ship.getXPosition();
            y_position = ship.getYPosition();

            // create implosion
            for( int i = 0; i < 20; i++ )
            {
                double warmupRadius = ShapeLib.shipLength * 3;

                Icing ic = new Icing(ship.getXPosition()
                        + (Math.random() * warmupRadius - warmupRadius / 2), ship.getYPosition()
                        + (Math.random() * warmupRadius - warmupRadius / 2),
                        (int) (0.25 * Utils.FRAMES_PER_SECOND));
                ic.setColor(Color.ORANGE);

                double direction = Utils.pointDirection(ic.getXPosition(), ic.getYPosition(),
                        ship.getXPosition(), ship.getYPosition())
                        + (Math.random() * 20 - 10);

                double speed = (ShapeLib.shipLength * 4) / Utils.FRAMES_PER_SECOND;
                ic.addVelocity(Utils.createPolarCoordinate(direction, speed));
                icing.add(ic);
                phaseStartTime = currentTime;
                phase = 1;
            }
        }
        else if( !ship.isAlive() && phase == 1
                && currentTime - phaseStartTime > Utils.FRAMES_PER_SECOND / 4.0 )
        {
            logger.trace("asploding!");

            // explode! - first create shrapnel
            double minShrapnels = (max_explosion_radius / ShapeLib.shipLength) * 35;
            for( int k = 0; k < (int) (Math.round(Math.random() * 50 + minShrapnels)); k++ )
            {
                int s = (int) (Math.random() * (ship.getMaxRadius() - 4)) + 4;

                Utils.CartesianCoordinate coord = Utils.cartesianFromPolar(Utils
                        .createPolarCoordinate(Math.random() * 360 + 1, ship.getMaxRadius() / 2));

                Utils.PolarCoordinate[] icingShape = { Utils.createPolarCoordinate(0, s / 2),
                        Utils.createPolarCoordinate(180, s / 2) };

                Icing i = new Icing(x_position + coord.getXComponent(), y_position
                        + coord.getYComponent(), (int) (Math.random() * (Utils.FRAMES_PER_SECOND)),
                        icingShape, GameObject.ObjectType.ICING);

                i.setRotation(Math.random() * 360);
                i.setRotationSpeed(Math.random() * 360 / (1.5 * Utils.FRAMES_PER_SECOND) + 2.5);
                // i.setVelocity(Math.random() * (300 / Utils.FRAMES_PER_SECOND)
                // - (150 / Utils.FRAMES_PER_SECOND), Math.random()
                // * (300 / Utils.FRAMES_PER_SECOND) - (150 /
                // Utils.FRAMES_PER_SECOND));
                Utils.PolarCoordinate pVelocity = Utils.createPolarCoordinate(
                        Math.random() * 360 + 1, (max_explosion_radius * 5)
                                / Utils.FRAMES_PER_SECOND);
                i.setVelocity(Utils.cartesianFromPolar(pVelocity));
                icing.add(i);
            }
            phaseStartTime = currentTime;
            phase = 2;
        }
        else if( phase == 2 )
        {
            logger.trace("expanding asplosion!");
            // expand explosion - looking for 1/10 of a second boom time
            double explosionTime = .1 * Utils.FRAMES_PER_SECOND;
            explosion_radius += max_explosion_radius / explosionTime;
            objectShape = Utils.createPolarCircle(explosion_radius);

            // kill things if they are too close
            ArrayList<GameObject> possibleTargets = new ArrayList<GameObject>();
            possibleTargets.addAll(state.getAsteroidManager().getObjects()); // include
                                                                             // all
                                                                             // asteroids

            for( Ship s : state.getShipManager().getObjects() )
            {
                if( !s.equals(ship) )
                {
                    possibleTargets.add(s);
                    possibleTargets.addAll(s.getObjects()); // add all Bullets
                }
            }

            Bullet killZone = new Bullet(x_position, y_position, 0, 0, 1,
                    Utils.createPolarCircle(explosion_radius), ship);
            for( GameObject other : possibleTargets )
            {
                if( Utils.gameObjectsCollide(killZone, other) && other.isAlive() )
                {
                    other.collide(killZone, killZone.getCollisionPower(other));
                }
            }

            // if explosion is over, end
            if( currentTime - phaseStartTime > explosionTime )
            {
                logger.trace("ending asplosion!");
                phase = 3; // prevent additional carnage
                drawMe = false;
            }
        }
        else if( phase == 3 && icing.size() == 0 )
        {
            logger.trace("asplosion nimation end");
            placeholder.destroy(); // allow the ship to RIP
        }
        currentTime++;
        super.update(state);
    }

    public void draw(Graphics g)
    {
        super.draw(g);
        if( phase == 1 )
        {
            // draw lines
            for( Icing i : icing )
            {
                g.setColor(Color.ORANGE);
                // if( Utils.pointDistance(i.getXPosition(), i.getYPosition(),
                // x_position, y_position) > Utils.GAME_WIDTH / 2 )
                if( Math.abs(i.getXPosition() - x_position) < Utils.GAME_WIDTH / 2
                        && Math.abs(i.getYPosition() - y_position) < Utils.GAME_HEIGHT / 2 )
                {
                    g.drawLine((int) i.getXPosition(), (int) i.getYPosition(), (int) x_position,
                            (int) y_position);
                }
            }
        }
        // if( phase == 2 )
        // {
        // g.drawOval((int) (x_position - explosion_radius),
        // (int) (y_position - explosion_radius), (int) explosion_radius * 2,
        // (int) explosion_radius * 2);
        // }
    }

    @Override
    public void respawn()
    {
        phase = 0;
        explosion_radius = 1;
        objectShape = Utils.createPolarCircle(explosion_radius);
        drawMe = false;
    }
}
